package es.aradesh.ministryassist.logic;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ListIterator;

import org.xmlpull.v1.XmlSerializer;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.util.Xml;
import es.aradesh.ministryassist.db.DbAdapter;
import es.aradesh.ministryassist.db.HomeColumns;
import es.aradesh.ministryassist.db.NoteColumns;
import es.aradesh.ministryassist.db.StreetColumns;
import es.aradesh.ministryassist.db.TerritoryColumns;
import es.aradesh.ministryassist.logic.ministry.Home;
import es.aradesh.ministryassist.logic.ministry.HomeBuilder;
import es.aradesh.ministryassist.logic.ministry.MinistryElement;
import es.aradesh.ministryassist.logic.ministry.Note;
import es.aradesh.ministryassist.logic.ministry.NoteBuilder;
import es.aradesh.ministryassist.logic.ministry.Street;
import es.aradesh.ministryassist.logic.ministry.StreetBuilder;
import es.aradesh.ministryassist.logic.ministry.Territory;
import es.aradesh.ministryassist.utils.Constants;

public class ExportTask extends AsyncTask<ExportTaskParams, Integer, Void> {

	private static final String MINISTRY_TAG = "Ministry";
	private static final String TERRITORY_TAG = "Territory";
	private static final String STREET_TAG = "Street";
	private static final String HOME_TAG = "Home";
	private static final String NOTE_TAG = "Note";

	private Context mContext;
	private Handler mGuiHandler;
	private OnExportFinishedListener mOnExportFinishedListener;

	public ExportTask(Context context) {
		mContext = context;
		mGuiHandler = new Handler();
	}

	public OnExportFinishedListener getOnExportFinishedListener() {
		return mOnExportFinishedListener;
	}

	public void setOnExportFinishedListener(OnExportFinishedListener listener) {
		mOnExportFinishedListener = listener;
	}

	@Override
	protected Void doInBackground(ExportTaskParams... params) {
		for (ExportTaskParams par : params) {
			final ExportTaskResult res = exportXML(par);

			mGuiHandler.post(new Runnable() {
				
				public void run() {
					if (mOnExportFinishedListener != null) {
						mOnExportFinishedListener.onExportFinished(res);
					}
				}
			});
		}
		return null;
	}

	private ExportTaskResult exportXML(ExportTaskParams par) {
		ExportTaskResult result = new ExportTaskResult();
		Writer writer = null;
		XmlSerializer serializer = Xml.newSerializer();
		DbAdapter mDb = new DbAdapter(mContext);
		mDb.open();

		Territory terri = null;
		Street street = null;
		Home home = null;
		Note note = null;

		ListIterator<Territory> iterri = null;
		ListIterator<Street> istreet = null;
		ListIterator<Home> ihome = null;
		Home[] ibuilding = null;
		ListIterator<Note> inote = null;

		result.successful = false;

		try {
			// create dir if it does not exists already
			File dir = new File(par.file.getParent());
			if (!dir.exists()) {
				dir.mkdirs();
			}

			result.file = par.file;
			writer = new BufferedWriter(new FileWriter(result.file, false));
			serializer.setOutput(writer);
			serializer.startDocument("UTF-8", true);
			serializer.startTag("", MINISTRY_TAG);
			if (!par.terris.isEmpty()) {
				iterri = par.terris.listIterator();
				while (iterri.hasNext()) {
					terri = iterri.next();
					serializer.startTag("", TERRITORY_TAG);
					fillAtributes(serializer, TerritoryColumns.ATRIBUTES, terri);
					istreet = StreetBuilder.getStreetsByTerritory(mDb, terri)
							.listIterator();
					while (istreet.hasNext()) {
						street = istreet.next();
						serializer.startTag("", STREET_TAG);
						fillAtributes(serializer, StreetColumns.ATRIBUTES,
								street);
						ihome = HomeBuilder.getHomesByStreet(mDb, street)
								.listIterator();
						while (ihome.hasNext()) {
							home = ihome.next();
							serializer.startTag("", HOME_TAG);
							fillAtributes(serializer, HomeColumns.ATRIBUTES,
									home);
							if (home.isBuilding()) {
								ibuilding = home.getFlats();
								for (int i = 0; i < ibuilding.length; i++) {
									serializer.startTag("", HOME_TAG);
									fillAtributes(serializer,
											HomeColumns.ATRIBUTES, ibuilding[i]);
									// fillnotes
									inote = NoteBuilder.getNotesByHome(mDb,
											ibuilding[i]).listIterator();
									while (inote.hasNext()) {
										note = inote.next();
										serializer.startTag("", NOTE_TAG);
										fillAtributes(serializer,
												NoteColumns.ATRIBUTES, note);
										serializer.endTag("", NOTE_TAG);
									}
									serializer.endTag("", HOME_TAG);
								}
							} else {
								// fillnotes
								inote = NoteBuilder.getNotesByHome(mDb, home)
										.listIterator();
								while (inote.hasNext()) {
									note = inote.next();
									serializer.startTag("", NOTE_TAG);
									fillAtributes(serializer,
											NoteColumns.ATRIBUTES, note);
									serializer.endTag("", NOTE_TAG);
								}
								serializer.endTag("", HOME_TAG);
							}
						}
						serializer.endTag("", STREET_TAG);
					}
					serializer.endTag("", TERRITORY_TAG);
				}
			}
			serializer.endTag("", MINISTRY_TAG);
		} catch (IOException e) {
			Log.e(Constants.TAG, "Error while exporting file.", e);
			result.successful = false;
			return result;
		} finally {
			if (mDb != null)
				mDb.close();
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					Log.e(Constants.TAG, "Error while exporting file.", e);
					result.successful = false;
					return result;
				}
			}
		}
		result.successful = true;
		return result;
	}

	private void fillAtributes(XmlSerializer ser, String[] atributes,
			MinistryElement element) throws IllegalArgumentException,
			IllegalStateException, IOException {
		Object value = null;
		for (int i = 0; i < atributes.length; i++) {
			value = element.getParam(atributes[i]);
			if (value != null) {
				ser.attribute("", atributes[i], value.toString());
			}
		}
	}

	public interface OnExportFinishedListener {
		/**
		 * Occurs when export is finished.
		 * 
		 * @param importSuccessful
		 *            Indicates whether export was successful.
		 * @param folderId
		 *            Contains id of imported folder, or -1 if multiple folders
		 *            were imported.
		 */
		void onExportFinished(ExportTaskResult result);
	}
}
